package com.cgc.venus.server.monitor.service;
import com.cgc.venus.server.core.base.AbstractBaseService;
import com.cgc.venus.server.core.bean.response.VenusResponseStatus;
import com.cgc.venus.server.core.exception.VenusException;
import com.cgc.venus.server.core.utils.DateUtil;
import com.cgc.venus.server.core.utils.StringUtil;
import com.cgc.venus.server.monitor.bean.MetricsType;
import com.cgc.venus.server.monitor.bean.MonitorQuery;
import com.cgc.venus.server.monitor.bean.MonitorResult;
import com.cgc.venus.server.monitor.bean.Series;
import com.cgc.venus.server.monitor.bean.influxdbmodal.InfluxdbResult;
import com.cgc.venus.server.monitor.inter.MonitorService;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBResultMapper;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 业哥 on 2017/11/8.
 */

@Service
@ConfigurationProperties(prefix = "influxdb")
public class MonitorServiceImpl extends AbstractBaseService implements MonitorService {
    private String url;
    private String userName;
    private String password;
    private String dbName;
    private InfluxDB influxDBClient;

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setDbName(String dbName) {
        this.dbName = dbName;
    }

    private InfluxDB getInfluxDBClient(){
        if(influxDBClient==null){
            influxDBClient = InfluxDBFactory.connect(url, userName, password);
            return influxDBClient;
        }
        return influxDBClient;
    }


    //集群
    private List clusterSearch(MetricsType metricsType,String start,String end) throws VenusException {
        String sql="select time,value from \""+metricsType.getName()+"\" where type='cluster' and time>='"+start+"' and time<='"+end+"'";
        QueryResult queryResult = getInfluxDBClient().query(new Query(sql, dbName));
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        List list = resultMapper.toPOJO(queryResult, metricsType.getClas());
        return list;
    }


    //node
    private List nodeSearch(MetricsType metricsType,String  nodeName,String start,String end) throws VenusException {
        String sql="select time,value from \""+metricsType.getName()+"\" where type='node' and nodename='"+nodeName+"' and time>='"+start+"' and time<='"+end+"'";
        QueryResult queryResult = getInfluxDBClient().query(new Query(sql, dbName));
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        List list = resultMapper.toPOJO(queryResult, metricsType.getClas());
        return list;
    }


    //namespace
    private List namespaceSearch(MetricsType metricsType,String  namespace,String start,String end) throws VenusException {
        String sql="select time,value from \""+metricsType.getName()+"\" where type='ns' and namespace_name='"+namespace+"' and time>='"+start+"' and time<='"+end+"'";
        QueryResult queryResult = getInfluxDBClient().query(new Query(sql, dbName));
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        List list = resultMapper.toPOJO(queryResult, metricsType.getClas());
        return list;
    }


    //pod
    private List podSearch(MetricsType metricsType,String  namespace,String podName,String start,String end) throws VenusException {
        String sql="select time,value from \""+metricsType.getName()+"\" where type='pod' and namespace_name='"+namespace+"' and pod_name='"+podName+"' and time>='"+start+"' and time<='"+end+"'";
        QueryResult queryResult = getInfluxDBClient().query(new Query(sql, dbName));
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        List list = resultMapper.toPOJO(queryResult, metricsType.getClas());
        return list;
    }

    @Override
    public MonitorResult monitorQuery(MonitorQuery monitorQuery) throws VenusException {
//        private String monitorType;    //监控类型  值为:memory/cpu/net-in/net-out
//        private String monitorObject; //监控对象  值为:cluster/namespace/node/pod
//        private String metricsType;   //监控指标类型 值参考heapster api
//        private String times;          //时间参数  如果为时间段 用逗号隔开
//        //======可选参数=========
//        private String nodeNames;      //当queryType为node时  nodeName为必填值 多个用逗号隔开
//        private String namespaceName; //当queryType为namespace时  namespaceName为必填值
//        private String podNames;       //当queryType为pod时,namespaceName,podName为必填值 多个用逗号隔开
        if(monitorQuery==null){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控查询参数为空!");
        }
        String monitorType=monitorQuery.getMonitorType();
        String monitorObject=monitorQuery.getMonitorObject();
        String metricsType=monitorQuery.getMetricsType();
        String times=monitorQuery.getTimes();
        //======可选参数=========
        String nodeNames=monitorQuery.getNodeNames();
        String namespaceName=monitorQuery.getNamespaceName();
        String podNames=monitorQuery.getPodNames();
        if(StringUtil.isEmpty(monitorType)){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控类型参数为空!");
        }
        if(StringUtil.isEmpty(monitorObject)){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控对象参数为空!");
        }
        if(StringUtil.isEmpty(metricsType)){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控指标参数为空!");
        }
        if(StringUtil.isEmpty(times)){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控时间参数为空!");
        }
        String[] timesArr=times.split(",");
        if(timesArr.length==0||timesArr.length>2){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控时间参数为空或时间格式为异常!");
        }
        if(!monitorType.equals("memory")&&!monitorType.equals("cpu")&&!monitorType.equals("net-in")&&!monitorType.equals("net-out")){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控类型参数为异常!");
        }
        if(!monitorObject.equals("cluster")&&!monitorObject.equals("namespace")&&!monitorObject.equals("node")&&!monitorObject.equals("pod")){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控对象参数为异常!");
        }
        MetricsType mt=null;
        for(MetricsType metricsType0:MetricsType.values()){
            if(metricsType0.getName().equals(metricsType)){
                mt=metricsType0;
                break;
            }
        }
        if(mt==null){
            throw new VenusException(VenusResponseStatus.NO_CONTENT, "监控指标参数为异常!");
        }
        //时间处理 start end
        String[] timePair=DateUtil.handleTimes2(times);
        String timeStart= timePair[0];
        String timeEnd= timePair[1];

        //时间处理 end

        //监控结果处理
        MonitorResult monitorResult=new MonitorResult();
        monitorResult.setTitle(mt.getDesc());
        monitorResult.setxName("时间");
        monitorResult.setyName("单位:"+calculateUnit(monitorQuery));

        //集群监控信息查询
        if(monitorObject.equals("cluster")){
            List<Object> legend=new ArrayList<Object>();
            legend.add("k8s集群");
            monitorResult.setLegend(legend);
            List resultPairs=clusterSearch(mt, timeStart,timeEnd);
            //if(resultPairs!=null&&resultPairs.size()>0){
                //List<ResultPair> resultPairs=rs.getMetrics();
                if(resultPairs!=null&&resultPairs.size()>0){
                    List<Object> xAxisData=new ArrayList<Object>();
                    List<Series> yAxisData=new ArrayList<Series>();
                    Series series=new Series();
                    List<Object> yAxisData1=new ArrayList<Object>();
                    for(Object obj:resultPairs){
                        InfluxdbResult rp= (InfluxdbResult) obj;
                        xAxisData.add(DateUtil.handleTimes3(times,rp.getTime()));
                        yAxisData1.add(calculateYValue(monitorQuery,rp.getValue()));
                    }
                    series.setName("k8s集群");
                    series.setData(yAxisData1);
                    yAxisData.add(series);
                    monitorResult.setxAxisData(xAxisData);
                    monitorResult.setyAxisData(yAxisData);
                }
           // }
        }

        //命名空间监控查询
        if(monitorObject.equals("namespace")){
            if(StringUtil.isEmpty(namespaceName)){
                throw new VenusException(VenusResponseStatus.NO_CONTENT, "命名空间参数为空!");
            }
            List<Object> legend=new ArrayList<Object>();
            legend.add(namespaceName);
            monitorResult.setLegend(legend);
            List resultPairs=namespaceSearch(mt,namespaceName,timeStart,timeEnd);
            //if(rs!=null){
                //List<ResultPair> resultPairs=rs.getMetrics();
                if(resultPairs!=null&&resultPairs.size()>0){
                    List<Object> xAxisData=new ArrayList<Object>();
                    List<Series> yAxisData=new ArrayList<Series>();
                    Series series=new Series();
                    List<Object> yAxisData1=new ArrayList<Object>();
                    for(Object obj:resultPairs){
                        InfluxdbResult rp= (InfluxdbResult) obj;
                        xAxisData.add(DateUtil.handleTimes3(times,rp.getTime()));
                        yAxisData1.add(calculateYValue(monitorQuery,rp.getValue()));
                    }
                    series.setName(namespaceName);
                    series.setData(yAxisData1);
                    yAxisData.add(series);
                    monitorResult.setxAxisData(xAxisData);
                    monitorResult.setyAxisData(yAxisData);
                }
            //}
        }
        //节点监控查询
        if(monitorObject.equals("node")){
            if(StringUtil.isEmpty(nodeNames)){
                throw new VenusException(VenusResponseStatus.NO_CONTENT, "节点参数为空!");
            }
            String[] nodes=nodeNames.split(",");
            if(nodes!=null&&nodes.length>0){
                List<Object> legend=new ArrayList<Object>();
                int i=0;
                List<Object> xAxisData=new ArrayList<Object>();
                List<Series> yAxisData=new ArrayList<Series>();
                for(String node:nodes){
                    legend.add(node);
                    List resultPairs=nodeSearch(mt,node,timeStart,timeEnd);
                    //List<ResultPair> resultPairs=rs.getMetrics();
                    if(resultPairs!=null&&resultPairs.size()>0){
                        Series series=new Series();
                        List<Object> yAxisData1=new ArrayList<Object>();
                        for(Object obj:resultPairs){
                            InfluxdbResult rp= (InfluxdbResult) obj;
                            if(i==0){
                                xAxisData.add(DateUtil.handleTimes3(times,rp.getTime()));
                            }
                            yAxisData1.add(calculateYValue(monitorQuery, rp.getValue()));
                        }
                        series.setName(node);
                        series.setData(yAxisData1);
                        yAxisData.add(series);
                    }
                    i++;
                }
                monitorResult.setxAxisData(xAxisData);
                monitorResult.setyAxisData(yAxisData);
                monitorResult.setLegend(legend);
            }
        }
        //pod(应用信息监控)
        if(monitorObject.equals("pod")){
            if(StringUtil.isEmpty(namespaceName)){
                throw new VenusException(VenusResponseStatus.NO_CONTENT, "命名空间参数为空!");
            }
            if(StringUtil.isEmpty(podNames)){
                throw new VenusException(VenusResponseStatus.NO_CONTENT, "podName参数为空!");
            }
            String[] pods=podNames.split(",");
            if(pods!=null&&pods.length>0){
                List<Object> legend=new ArrayList<Object>();
                int i=0;
                List<Object> xAxisData=new ArrayList<Object>();
                List<Series> yAxisData=new ArrayList<Series>();
                for(String pod:pods){
                    legend.add(pod);
                    List resultPairs=podSearch(mt,namespaceName,pod,timeStart,timeEnd);
                    //List<ResultPair> resultPairs=rs.getMetrics();
                    if(resultPairs!=null&&resultPairs.size()>0){
                        Series series=new Series();
                        List<Object> yAxisData1=new ArrayList<Object>();
                        for(Object obj:resultPairs){
                            InfluxdbResult rp= (InfluxdbResult) obj;
                            if(i==0){
                                xAxisData.add(DateUtil.handleTimes3(times,rp.getTime()));
                            }
                            yAxisData1.add(calculateYValue(monitorQuery, rp.getValue()));
                        }
                        series.setName(pod);
                        series.setData(yAxisData1);
                        yAxisData.add(series);
                    }
                    i++;
                }
                monitorResult.setxAxisData(xAxisData);
                monitorResult.setyAxisData(yAxisData);
                monitorResult.setLegend(legend);
            }
        }
        return monitorResult;
    }

    /**
     * 单位计算
     * @param monitorQuery
     * @return
     */
    private String calculateUnit(MonitorQuery monitorQuery){
        String monitorObject= monitorQuery.getMonitorObject();
        String metricsType =monitorQuery.getMetricsType();
        if(metricsType.indexOf("cpu")!=-1){
            //cpu 计算单位
            return "核";
        }
        if(metricsType.indexOf("memory")!=-1){
            //memory 计算单位
            //cluster/namespace/node/pod
            if(monitorObject.equals("cluster")||monitorObject.equals("namespace")||monitorObject.equals("node")){
                return "GB";
            }else{
                return "MB";
            }
        }
        if(metricsType.indexOf("net")!=-1){
            //网络 计算单位
            return "KB";
        }
        return "";
    }

    /**
     * y值计算
     * @param monitorQuery
     * @param value
     * @return
     */
    private Object calculateYValue(MonitorQuery monitorQuery,Object value){
        String monitorObject= monitorQuery.getMonitorObject();
        String metricsType =monitorQuery.getMetricsType();
        if(metricsType.indexOf("cpu")!=-1){
            //cpu 解析
            Long l= (Long) value;
            BigDecimal bigDecimal=new BigDecimal(l);
            return bigDecimal.divide(new BigDecimal(1000),3,BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        if(metricsType.indexOf("memory")!=-1){
            //memory 计算单位
            //cluster/namespace/node/pod
            Long l= (Long) value;
            BigDecimal bigDecimal=new BigDecimal(l);

            if(monitorObject.equals("cluster")||monitorObject.equals("namespace")||monitorObject.equals("node")){
                //GB
                return bigDecimal.divide(new BigDecimal(1024*1024*1024),1,BigDecimal.ROUND_HALF_UP).doubleValue();
            }else{
                //MB
                return bigDecimal.divide(new BigDecimal(1024*1024),0,BigDecimal.ROUND_HALF_UP);
            }
        }
        if(metricsType.indexOf("net")!=-1){
            //网络 计算单位 kb
            Long l= (Long) value;
            BigDecimal bigDecimal=new BigDecimal(l);
            return bigDecimal.divide(new BigDecimal(1024),1,BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        return "";
    }

}